﻿using AutoMapper;
using DataServer.ApplicationLib.Entities;
using DataServer.ApplicationLib.Repositories;
using Microsoft.Extensions.DependencyInjection;
using System.Data;
using Swimj.DataCore;

namespace DataServer.ApplicationLib.Rules
{
    public class ConfigDataRuleDefault : ConfigDataRuleBase
    {
        private const string tempCheckTable = ConfigDataTableCheck.TableName;

        public bool AddedTempRowID { get; set; }

        public ConfigDataRuleDefault(RuleContext ruleContext) : base(ruleContext)
        {
        }

        public override async Task<VerifyRuleResult> VerifyData()
        {
            AddedTempRowID = false;
            //var needTransferTextVal = false;

            var result = new VerifyRuleResult();
            var data = RuleContext.TargetData;
            if (RuleContext.RequestId == null)
                RuleContext.RequestId = Guid.NewGuid();

            if (data != null && data.Rows.Count > 0)
            {
                if (Successor != null)
                {
                    var haveDbCheckRule = HaveDbCheckRule();

                    //将数据写入check table
                    if (haveDbCheckRule)
                    {
                        await WriteDataToCheckTable(data);
                    }

                    result = await this.Successor.VerifyData();
                }
                else
                {
                    result.IsValid = true;
                }
            }
            else
            {
                result.Message = "数据列表为空，不需要进行校验";
            }

            if (result != null)
            {
                if (!result.IsValid && string.IsNullOrEmpty(result.Message))
                {
                    if (result.Data != null && RuleHelper.GetInvalidRowCount(result.Data) > 0)
                    {
                        result.Message = "发现不合法的数据，详见明显.";
                    }
                }

                result.RequestId = RuleContext.RequestId;
            }
            return result;
        }

        private async Task WriteDataToCheckTable(DataTable data)
        {
            var repo = RuleContext.ServiceProvider.GetRequiredService<IConfigDataCheckRepository>();
            DataTable checkData = data.DefaultView.ToTable();
            AddAuditableInfo(checkData);
            AddRequestID(checkData);
            if (this.RuleContext.StoreCheckColMap.Any(item => item.Key != item.Value))
            {
                foreach (var item in this.RuleContext.StoreCheckColMap)
                {
                    if (checkData.Columns.Contains(item.Key) && item.Key != item.Value)
                    {
                        checkData.Columns[item.Key]!.ColumnName = item.Value;
                    }
                }
            }
            // 先将数据写入Check表：包含DATA的所有列+MESSAGE+ISValid+Request_ID

            var mapper = RuleContext.ServiceProvider.GetRequiredService<IMapper>();
            var checklist = mapper.Map<IDataReader, IEnumerable<ConfigDataCheckEntity>>(checkData.CreateDataReader());
            
            await repo.BatchInsertAsync(checklist);
            var unitOfWork = RuleContext.ServiceProvider.GetRequiredService<IUnitOfWork>();
            unitOfWork.Commit();
        }

        private void AddAuditableInfo(DataTable data)
        {
            if (data != null && data.Rows.Count > 0)
            {
                if (!data.Columns.Contains(CommonAuditing.CreatedBy))
                {
                    DataColumn CreateByColumn = new DataColumn(CommonAuditing.CreatedBy);
                    CreateByColumn.DataType = typeof(string);
                    CreateByColumn.DefaultValue = RuleContext.CurrentUserName;
                    data.Columns.Add(CreateByColumn);
                }

                if (!data.Columns.Contains(CommonAuditing.CreationDate))
                {
                    DataColumn CreationDateColumn = new DataColumn(CommonAuditing.CreationDate);
                    CreationDateColumn.DataType = typeof(DateTime);
                    CreationDateColumn.DefaultValue = DateTime.Now;
                    data.Columns.Add(CreationDateColumn);
                }

                if (!data.Columns.Contains(CommonAuditing.LastUpdatedBy))
                {
                    DataColumn LastUpdatedByColumn = new DataColumn(CommonAuditing.LastUpdatedBy);
                    LastUpdatedByColumn.DataType = typeof(string);
                    LastUpdatedByColumn.DefaultValue = RuleContext.CurrentUserName;
                    data.Columns.Add(LastUpdatedByColumn);
                }

                if (!data.Columns.Contains(CommonAuditing.LastUpdateDate))
                {
                    DataColumn LastUpdateDateColumn = new DataColumn(CommonAuditing.LastUpdateDate);
                    LastUpdateDateColumn.DataType = typeof(DateTime);
                    LastUpdateDateColumn.DefaultValue = DateTime.Now;
                    data.Columns.Add(LastUpdateDateColumn);
                }
            }
        }

        private void AddRequestID(DataTable checkData)
        {
            if (!checkData.Columns.Contains(ConfigDataTableCheck.RequestID))
            {
                DataColumn requestID = new DataColumn(ConfigDataTableCheck.RequestID);
                requestID.DataType = Type.GetType("System.Guid");
                requestID.DefaultValue = this.RuleContext.RequestId;
                checkData.Columns.Add(requestID);
            }
        }

        private bool HaveDbCheckRule()
        {
            var haveDbCheckRule = false;

            if (RuleContext.ConfigInfo != null &&
                RuleContext.ConfigInfo.CheckWay == DataCheckWay.InDB)
            {
                haveDbCheckRule = true;
            }

            if (!haveDbCheckRule)
            {
                if (RuleContext.ConfigRuleInfos != null &&
                    RuleContext.ConfigRuleInfos.Any(i => i.CheckWay == DataCheckWay.InDB))
                {
                    haveDbCheckRule = true;
                }
            }

            return haveDbCheckRule;
        }
    }
}